﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml.Serialization;

namespace ArgusLight.Fractals2D.ComplexFractalColoring.RouteLengthBased
{
	[XmlType(TypeName="ComplexRouteLengthBasedColoring")]
	public abstract class Coloring : ComplexFractalColoring.PeriodicColoring
	{
		/// <summary>
		/// Type: <see cref="ColoringData"/>
		/// </summary>
		public override Fractals2D.ColoringData Data
		{
			get
			{
				return this._data;
			}
			protected set
			{
				if ((value is ColoringData) == true)
					this._data = (ColoringData)value;
			}
		}
		private ColoringData _data;
		protected new ColoringData data { get { return (ColoringData)this.Data; } }

		public Coloring()
			: base() { }

		public override void Reset(FractalParameter fParameter)
		{
			base.Reset(fParameter);
			this.Data = new ColoringData(fParameter.PixelWidth, fParameter.PixelHeight);
		}

		public override void z_set(int x, int y, System.Numerics.Complex value)
		{
			this.data.routeLength[x, y] += (this.data.z[x, y] - value).Magnitude;
			base.z_set(x, y, value);
		}

		public override void PostCalculation()
		{
			base.PostCalculation();
			for (int x = 0; x < this.fractalParameter.PixelWidth; x++)
			{
				for (int y = 0; y < this.fractalParameter.PixelHeight; y++)
				{
					int i = this.data.iterations[x, y];
					if (i < 1 || i >= this.fractalParameter.Iterations)
						continue;
					double l = this.data.routeLength[x, y];
					if (l < this.data.ArgumentInterval.Min)
						this.data.ArgumentInterval.Min = l;
					if (l > this.data.ArgumentInterval.Max)
						this.data.ArgumentInterval.Max = l;
				}
			}
		}

		protected override double GetFrequency()
		{
			return 2 * this.parameter.NumberOfColorPeriods * System.Math.PI / this.data.ArgumentInterval.Length;
		}

		#region GetColorBytes
		private const double const_p2 = 2 * System.Math.PI / 3;
		private const double const_p3 = 4 * System.Math.PI / 3;

		public static byte[] GetBytes_Sinus2(Int32 i, Int32 MaxI, Double RouteLength, Double Frequency, Double Translation)
		{
			if (i >= MaxI || i < 1)
				return new byte[] { 0, 0 };

			byte a, b;
			a = b = 0;

			Translation *= 2 * Math.PI;

			a = (byte)((System.Math.Sin(RouteLength * Frequency + Translation) + 1) * 127);
			b = (byte)((System.Math.Sin(RouteLength * Frequency + System.Math.PI + Translation) + 1) * 127);

			return new byte[] { a, b };
		}

		public static byte[] GetBytes_2(Int32 i, Int32 MaxI, Double RouteLength, Double Frequency, Double Translation)
		{
			if (i >= MaxI || i < 1)
				return new byte[] { 0, 0 };

			int a = (int)((System.Math.Sin(RouteLength * Frequency + Translation) + 1) * 255);

			byte[] b = new byte[2];
			if (a < 256)
			{
				b[0] = (byte)(a);
				b[1] = 0;
			}
			else
			{
				b[0] = 255;
				b[1] = (byte)(a - 255);
			}

			return b;
		}

		public static byte[] GetBytes_3(Int32 i, Int32 MaxI, Double RouteLength, Double Frequency, Double Translation)
		{
			if (i >= MaxI || i < 1)
				return new byte[] { 0, 0, 0 };

			int a = (int)((System.Math.Sin(RouteLength * Frequency + Translation) + 1) * 255 * 3 / 2);

			byte[] b = new byte[3];
			if (a < 256)
			{
				b[0] = (byte)(a);
				b[1] = 0;
				b[2] = 0;
			}
			else if (a <= 2 * 255)
			{
				b[0] = 255;
				b[1] = (byte)(a - 255);
				b[2] = 0;
			}
			else
			{
				b[0] = 255;
				b[1] = 255;
				b[2] = (byte)(a - 2 * 255);
			}

			return b;
		}

		public static byte[] GetBytes_Sinus3(Int32 i, Int32 MaxI, Double RouteLength, Double Frequency, Double Translation)
		{
			if (i >= MaxI || i < 1)
				return new byte[] { 0, 0, 0 };

			byte a, b, c;
			a = b = c = 0;

			Translation *= 2 * Math.PI;

			a = (byte)((System.Math.Sin(RouteLength * Frequency + Translation) + 1) * 127);
			b = (byte)((System.Math.Sin(RouteLength * Frequency + const_p2 + Translation) + 1) * 127);
			c = (byte)((System.Math.Sin(RouteLength * Frequency + const_p3 + Translation) + 1) * 127);

			return new byte[] { a, b, c };
		}

		public static byte[] GetBytes_Sinus3(Int32 i, Int32 MaxI, Double RouteLength, Double Frequency, Double Translation, Int32[] amplitude)
		{
			if (i >= MaxI || i < 1)
				return new byte[] { 0, 0, 0 };

			byte a, b, c;
			a = b = c = 0;

			Translation *= 2 * Math.PI;

			a = (byte)((System.Math.Sin(RouteLength * Frequency + Translation) + 1) * amplitude[0] / 2);
			b = (byte)((System.Math.Sin(RouteLength * Frequency + const_p2 + Translation) + 1) * amplitude[1] / 2);
			c = (byte)((System.Math.Sin(RouteLength * Frequency + const_p3 + Translation) + 1) * amplitude[2] / 2);

			return new byte[] { a, b, c };
		}
		#endregion
	}
}
